#ifndef __INCLUDE_MANAGER_H
#define __INCLUDE_MANAGER_H

#include <list>
#include <unordered_map>
#include <fstream>

#include "customer.h"
#include "staff.h"

class Manager {
public:
    friend class Ui;

    enum {
        CUSTOMER = 0,
        STAFF,
        TABLE_TYPE_COUNT,
        ID = 0,
        NAME,
        PHONE,
        QUERY_TABLE_COUNT,
    };

    enum ServiceStatus {
        SUCCESS,
        BAD_PROJECT,
        BAD_CUSTOMERID,
        BAD_STAFFID,
        MISMATCHING,
    };

    struct TableBlock {
        using ListType = std::list<Human*>;

        ListType list;

        std::unordered_map<std::string, ListType::iterator>
            query_table[QUERY_TABLE_COUNT];
    };

private:
    TableBlock member_table[TABLE_TYPE_COUNT];

public:
    inline Manager() {}
    ~Manager();

    inline bool Contains(uint32_t type, uint32_t query_type,
                         std::string& msg) const {
        if (type >= TABLE_TYPE_COUNT || query_type >= QUERY_TABLE_COUNT)
            return false;

        auto&& table = member_table[type].query_table[query_type];
        return table.find(msg) != table.end();
    }

    inline Human* Query(uint32_t type, uint32_t query_type, std::string& msg) {
        return *(member_table[type].query_table[query_type].at(msg));
    }

    void Edit(uint32_t type, uint32_t query_type, Human* proto, std::string& new_val);

    ServiceStatus GiveService(Project::Type project_type, std::string& cust_id,
                              std::string& serv_id);

    bool Append(uint32_t type, Human* new_mem);
    bool Remove(uint32_t type, uint32_t query_type, std::string& msg);

    void Display(uint32_t type) const;
    void Display(Human* human) const;

    void Stats(uint32_t type) const;

    void Load(uint32_t type, std::fstream& fs);
    void Save(uint32_t type, std::fstream& fs) const;
};

#endif